#include "ramp.h"
#include "util/mmgr.h"		    
#include "util/common_macros.h"		
#include <cassert>
#include <algorithm>
using namespace math;


Ramp::Ramp()
{
	Reset();
}

Ramp::~Ramp()
{

}

float	Ramp::GetValue(float Pos)
{
	int	Index = (int)(Pos * RAMP_SIZE);
	UTIL_CLAMP(Index, 0, RAMP_SIZE-1);
	return m_RampA[Index];
}

void	Ramp::GetByIndex(int Index, float& Value, float& Position)
{
	UTIL_CLAMP(Index, 0, (int)(m_Values.size())-1);
	Value = m_Values[Index].Value;
	Position = m_Values[Index].Value;
}

void	Ramp::AddValue(float Value, float Position)
{
	ValueInst Inst;
	Inst.Value = Value;
	Inst.Position = Position;
	UTIL_CLAMP(Inst.Position, 0, 1);
	m_Values.push_back(Inst);
}

void	Ramp::Recalc()
{
	// easy out
	if (m_Values.empty())
	{
		Reset();
		return ;
	}	
	// do the math
	int	Index = 0;
	std::sort(m_Values.begin(), m_Values.end(), ValueInst::SortValues);
	
	float	Min = m_Values[0].Position;
	float	Max = m_Values[m_Values.size()-1].Position;

	for (unsigned int i=0; i<m_Values.size()-1; i++)
	{
		float	FromVal = m_Values[i].Value;
		float	ToVal	= m_Values[i+1].Value;
		float	From	= (m_Values[i].Position - Min) / (Max-Min);
		float	To		= (m_Values[i+1].Position - Min) / (Max-Min);

		// calc the area 
		int	A = (int)(From * RAMP_SIZE);
		int	B = (int)(To * RAMP_SIZE);
		UTIL_CLAMP(A, 0, RAMP_SIZE-1);
		UTIL_CLAMP(B, 0, RAMP_SIZE-1);
		float	dt = (ToVal-FromVal) / (float)(B-A);

		for (int j=A; j<=B; j++)
		{
			m_RampA[j] = FromVal + (dt * float(j-A));
		}
	}
	int j=0;
/*	float Val = m_Values[m_Values.size()-1].Value;
	for (unsigned int i=Index; i<RAMP_SIZE; i++)
	{
		m_RampA[i] = Val;
	}*/
}
void	Ramp::Reset()
{
	m_Values.resize(0);
	for (unsigned int i=0; i<RAMP_SIZE; i++)
		m_RampA[i] = 0.0f;

}

void	Ramp::Set( Ramp* pInput)
{
	if (!pInput) return;
	for (unsigned int i=0; i<pInput->m_Values.size(); i++)
	{
		ValueInst Inst;
		Inst.Value		= pInput->m_Values[i].Value;
		Inst.Position	= pInput->m_Values[i].Position;
		UTIL_CLAMP(Inst.Position, 0, 1);
		m_Values.push_back(Inst);
	}
	Recalc();
}


